//
//  HACAppDelegateDispatcher.m
//  HACDispatcher
//
//  Created by Chengjie on 2019/5/9.
//

#import "HACAppDelegateDispatcher.h"

@interface HACAppDelegateDispatcher ()
@property (nonatomic, strong) NSMutableArray<id<UIApplicationDelegate>> *appDelegates;

@end

@implementation HACAppDelegateDispatcher

- (instancetype)initWithDlegates:(NSArray<NSString *> *)delegates {
    self = [super init];
    if (self) {
        self.appDelegates = [NSMutableArray arrayWithCapacity:delegates.count];
        [delegates enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            Class cls = NSClassFromString(obj);
            id<UIApplicationDelegate> delegate = [[cls alloc] init];
            [self.appDelegates addObject:delegate];
        }];
    }
    return self;
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationDidFinishLaunching:application];
        }
    }];
}

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application willFinishLaunchingWithOptions:launchOptions] ?: returnValue;
        }
    }];
    return returnValue;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application didFinishLaunchingWithOptions:launchOptions] ?: returnValue;
        }
    }];
    return returnValue;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationDidBecomeActive:application];
        }
    }];
}

- (void)applicationWillResignActive:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationWillResignActive:application];
        }
    }];
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application handleOpenURL:url] ?: returnValue;
        }
    }];
    return returnValue;
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application openURL:url sourceApplication:sourceApplication annotation:annotation] ?: returnValue;
        }
    }];
    return returnValue;
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:app openURL:url options:options] ?: returnValue;
        }
    }];
    return returnValue;
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationDidReceiveMemoryWarning:application];
        }
    }];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationWillTerminate:application];
        }
    }];
}

- (void)applicationSignificantTimeChange:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationSignificantTimeChange:application];
        }
    }];
}

- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration  {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application willChangeStatusBarOrientation:newStatusBarOrientation duration:duration];
        }
    }];
}

- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didChangeStatusBarOrientation:oldStatusBarOrientation];
        }
    }];
}

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application willChangeStatusBarFrame:newStatusBarFrame];
        }
    }];
}
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didChangeStatusBarFrame:oldStatusBarFrame];
        }
    }];
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didRegisterUserNotificationSettings:notificationSettings];
        }
    }];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
        }
    }];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didFailToRegisterForRemoteNotificationsWithError:error];
        }
    }];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didReceiveRemoteNotification:userInfo];
        }
    }];
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didReceiveLocalNotification:notification];
        }
    }];
}


- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleActionWithIdentifier:identifier forRemoteNotification:userInfo withResponseInfo:responseInfo completionHandler:completionHandler];
        }
    }];
}


- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleActionWithIdentifier:identifier forRemoteNotification:userInfo completionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
        }
    }];
    
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application performFetchWithCompletionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void(^)(BOOL succeeded))completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application performActionForShortcutItem:shortcutItem completionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleEventsForBackgroundURLSession:identifier completionHandler:completionHandler];
        }
    }];
}

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(nullable NSDictionary *)userInfo reply:(void(^)(NSDictionary * __nullable replyInfo))reply {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application handleWatchKitExtensionRequest:userInfo reply:reply];
        }
    }];
}

- (void)applicationShouldRequestHealthAuthorization:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationShouldRequestHealthAuthorization:application];
        }
    }];
}

- (void)application:(UIApplication *)application handleIntent:(INIntent *)intent completionHandler:(void(^)(INIntentResponse *intentResponse))completionHandler {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            if (@available(iOS 11.0, *)) {
                [obj application:application handleIntent:intent completionHandler:completionHandler];
            } else {
                // Fallback on earlier versions
            }
        }
    }];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationDidEnterBackground:application];
        }
    }];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationWillEnterForeground:application];
        }
    }];
}

- (void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application  {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationProtectedDataWillBecomeUnavailable:application];
        }
    }];
}

- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application  {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj applicationProtectedDataDidBecomeAvailable:application];
        }
    }];
}

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window  {
    __block UIInterfaceOrientationMask returnValue = UIInterfaceOrientationMaskPortrait;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = returnValue | [obj application:application supportedInterfaceOrientationsForWindow:window];
        }
    }];
    return returnValue;
}

- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application shouldAllowExtensionPointIdentifier:extensionPointIdentifier] ?: returnValue;
        }
    }];
    return returnValue;
}

- (nullable UIViewController *) application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder {
    __block UIViewController *returnValue = nil;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application viewControllerWithRestorationIdentifierPath:identifierComponents coder:coder] ?: returnValue;
        }
    }];
    return returnValue;
}

- (BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = returnValue || [obj application:application shouldSaveApplicationState:coder];
        }
    }];
    return returnValue;
}

- (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = returnValue || [obj application:application shouldRestoreApplicationState:coder];
        }
    }];
    return returnValue;
}

- (void) application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application willEncodeRestorableStateWithCoder:coder];
        }
    }];
}

- (void) application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didDecodeRestorableStateWithCoder:coder];
        }
    }];
}


- (BOOL)application:(UIApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application willContinueUserActivityWithType:userActivityType] ?: returnValue;
        }
    }];
    return returnValue;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
    __block BOOL returnValue = NO;
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            returnValue = [obj application:application continueUserActivity:userActivity restorationHandler:restorationHandler] ?: returnValue;
        }
    }];
    return returnValue;
}

- (void)application:(UIApplication *)application didFailToContinueUserActivityWithType:(NSString *)userActivityType error:(NSError *)error {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didFailToContinueUserActivityWithType:userActivityType error:error];
        }
    }];
}
- (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didUpdateUserActivity:userActivity];
        }
    }];
}

- (void) application:(UIApplication *)application userDidAcceptCloudKitShareWithMetadata:(CKShareMetadata *)cloudKitShareMetadata {
    [self.appDelegates enumerateObjectsUsingBlock:^(id<UIApplicationDelegate>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:_cmd]) {
            if (@available(iOS 10.0, *)) {
                [obj application:application userDidAcceptCloudKitShareWithMetadata:cloudKitShareMetadata];
            } else {
                // Fallback on earlier versions
            }
        }
    }];
}


@end
